home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Libraries / GrafSys 2.0 / GrafSys 2.0 source / GrafSysCore.p < prev    next >
Encoding:
Text File  |  1993-07-27  |  26.7 KB  |  709 lines  |  [TEXT/PJMM]

  1. unit GrafSysCore;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Matrix, Transformations;
  7.  
  8.     const
  9.     {Misc Constants }
  10.         Res3D = '3Dob'; (* This is the 3D object data resource name *)
  11.         Res3DColor = 'lClr'; (* line color resource for 3Dob *)
  12.  
  13.     {Error Codes defined by the GrafSys }
  14.         cNoFFallocated = -1;
  15.         cOutOfMem = -2;
  16.         cBadMethodCall = -3; {this method should not be called. Instance it yourself!}
  17.         cNothingToInherit = -4; {this error occures when you try to pass on as first thing in the FF chain }
  18.         cTooManyPoints = -5; {model database is full. Maximum # of points exceeded }
  19.         cIllegalPointIndex = -6; {point index specified has no corresponding point in model }
  20.         cTooManyLines = -7; {trying to add a line to a model that is full }
  21.         cIllegalLineIndex = -8; {trying to access a line that does not exist }
  22.         cCantDeletePoint = -9; {the point is still referenced by at least one line}
  23.         cNotOwner = -10; {FF matrix doesn't belong to this object}
  24.         cBadFF = -11;    {FF matrix was NIL}
  25.         cBadFFType = -12; {FF matrix type cant be made current }
  26.         cCantLoadRes = -13; {error loading resource }
  27.         cNo3DWindow = -14; {Window passed is no 3D window }
  28.         cCantCreateOffscreen = -15; {Error occured while trying to allocate Off-Screen PixMap}
  29.         cCantChangeOffscreen = -16; {Error occured while trying to resize or recolor Off-Screen PixMap}
  30.         cNoOSAttached = -17; {the 3D Window passed has no Off-Screen PixMap attached}
  31.         cCantUseWindowCLUT = -18; {Current active window does not use indexed (1-8 bit/pixel) colors}
  32.         cNoActiveOSPixMap = -19; {User did not call BeginOSDraw. no active pix map}
  33.     {other constants}
  34.         cErrorAlertID = 32700; {standard error-handler alert }
  35.  
  36.     type
  37.         TGenericObject = object
  38.                 ErrorCode: integer;
  39.                 function Clone: TGenericObject;
  40.                 procedure Kill; (* deallocate myself *)
  41.                 procedure HandleError;
  42.                 procedure ResetError;
  43.                 function Test (opcode: integer): integer; (* does anything to check integrity of object         *)
  44.                                                         (* This incarnation just pops up the Error Dialog    *)
  45.                                                         (* and returns Error Code. Opcode is ignored         *)
  46.                 procedure Init;                                (* just so it is defined for every object. Does nothing     *)
  47.                                                         (* but initialization of ErrorCode. Make sure you do this *)
  48.                                                         (* first, then do your own init if no error reported        *)
  49.                 procedure Reset;                            (* reset this object. doesn't really do anything but provided *)
  50.                                                         (* so all objects support this method *)
  51.             end;
  52.  
  53.  
  54.         TMatrixList = object(TGenericObject)
  55.                 M: Matrix4;
  56.                 next: TMatrixList;
  57.                 owner: TGenericObject;                            {who owns this matrix? }
  58.                 procedure Init; (* set matrix to identity *)
  59.                 override;
  60.                 procedure Reset;
  61.                 override;
  62.                 procedure TMRotate (dx, dy, dz: real);        {rotate this matrix further}
  63.                 procedure TMScale (dx, dy, dz: real);        {scale this matrix further }
  64.                 procedure TMTranslate (dx, dy, dz: real);    {Translate this matrix further }
  65.                 procedure TMRotArbAchsis (p, x: Vector4; phi: real); {rotate around achsis defined by p and x}
  66.             end;
  67.  
  68.         TMatrixInherit = object(TMatrixList)     {This links a string of inherited matrixes to a 'father' }
  69.                 upLink: TMatrixList;                        {M contains the result of all MxM multiplie of prior }
  70.                                                     {Matrices. M is updated via the downlink whenever  }
  71.                                                     {father object gets updated. Update from father}
  72.                 meTheSon: Tabstract3DObject;            {link to myself. Used for killing son when father gets}
  73.                                                     {kill message, father accesses this field via downlink}
  74.                 procedure Init;
  75.                 override;
  76.             end;
  77.  
  78.         TMatrixPass = object(TMatrixList)        {this links a FFmatrix-string (up to here) to a son}
  79.                 downLink: TMatrixInherit;                {whenever Transform is called, it will place the current }
  80.                                                     {result of the FF transformations in the downlinks M field }
  81.                 meTheFather: Tabstract3DObject;        {link to myself}
  82.                 procedure Init;
  83.                 override;
  84.             end;
  85.  
  86.  
  87.         Tabstract3DObject = object(TGenericObject)
  88.                 xTrans, yTrans, zTrans: real;    {translation for origin}
  89.                 xScale, yScale, zScale: Real;    {scale factors for object}
  90.                 xrot, yrot, zrot: real;             { rotation in radiants }
  91.                 xForm: Matrix4;                    { result of all xforms including freeform }
  92.                 arbRot: Matrix4;                    { arbitrary rotation is stored here }
  93.                 currentFF: TMatrixList;            {current FF matrix}
  94.                 FFMatrix: TMatrixList;            { listhead of freeform xform matrices }
  95.                 objChanged: Boolean;             {true if object description changed. A call to calcTransform will reset it}
  96.                 versionsID: longint;                {used for sync with eye. If ID <> eyes ID a recalc is required }
  97.                 hasChanged: boolean;                {true after calctransform call that changed data. Should be reset by Draw etc. }
  98.                 procedure Init;                                        {initialize object}
  99.                 override;
  100.                 procedure Reset;                                    {reset all rot, trans, scale to default }
  101.                 override;
  102.                 function Clone: TGenericObject;                    {must also clone all TMatrix }
  103.                 override;                                                {ATTN: what about inheritances??}
  104.                 procedure Translate (dx, dy, dz: real);             { xlate object }
  105.                 procedure SetTranslation (x, y, z: real);         { set xlation to fixed amount }
  106.                 procedure Rotate (dx, dy, dz: real);                  { rotate further (just changes x-,y- and zrot) }
  107.                 procedure SetRotation (x, y, z: real);              { set rot to x,y and z }
  108.                 procedure Scale (dx, dy, dz: real);                  {scale factor for x, y and z }
  109.                 procedure SetScale (x, y, z: real);                  {set absolute scale factor }
  110.                 procedure RotArb (p, x: Vector4; phi: real);    {rotate around arbitrary axis}
  111.                 procedure ResetArb;                                {reset arb operator to identity}
  112.                 procedure FFTranslate (dx, dy, dz: real);          {xlate current FFMatrix further}
  113.                 procedure FFRotate (dx, dy, dz: real);              {rotate current FFMatrix further }
  114.                 procedure FFScale (dx, dy, dz: real);              {scale current FFMatrix further }
  115.                 procedure FFRotArbAchsis (p, x: Vector4; phi: real); {rotate around achsis defined by p and x}
  116.                 procedure FFReset;                                {resets *current* FFMatrix to Identity (i.e. not all) }
  117.                 function FFNewPostConcat: TMatrixList;             {allocate new FF matrix and postconcat it, put it into currentFF}
  118.                 function FFNewPreConcat: TMatrixList;            {allocate new FF matrix and preconcat it, put it into currentFF }
  119.                 function FFActivate (theFF: TMatrixList): boolean;
  120.                                                                 {puts theFF into currentFF. Returns true if successful}
  121.                 function FFPassOn: TMatrixPass;                    {generates a link for inheritance to 'son' object. I'm Father}
  122.                                                                 {it appends a link field to the FFMatrix list}
  123.                                                                 {does not update currentFF field}
  124.                 procedure FFInherit (var FatherList: TMatrixPass);    {Preconcatenate Fathers list to current FF List }
  125.                 procedure CalcTransform;                        {calculate xForm from rot,koord,scale and FF }
  126.                 function ForeignPoint (p: Vector4): Vector4;    {convert p using current object's xForm. Call Transform first!}
  127.                 function WorldToModel (wc: Vector4): Vector4; {xform world coordinates to model coordinates}
  128.                 procedure Draw;                                    {not supported at this level }
  129.                 procedure Kill;                                        {deallocate memory for this object. it will call kill for }
  130.                 override;                                                {all associated FF matrices. If it passes on, it will deallocate }
  131.                                                                 {all sons and their FF matrices as well}
  132.             end;
  133.  
  134.         TPoint3D = object(Tabstract3DObject)
  135.                 Koord: Vector4;
  136.                 procedure Init;
  137.                 override;
  138.                 procedure Reset;
  139.                 override;
  140.                 procedure SetKoords (Koordinates: Vector4);
  141.                 function GetKoords: Vector4;
  142.             end;
  143.  
  144.         TLine3D = object(Tabstract3DObject)
  145.                 FromLoc: Vector4;
  146.                 ToLoc: Vector4;
  147.                 procedure Init;
  148.                 override;
  149.                 procedure Reset;
  150.                 override;
  151.                 procedure SetKoords (K1, K2: Vector4);
  152.                 procedure GetKoords (var K1, K2: Vector4);
  153.             end;
  154.  
  155. (* return the error string that belongs to an error code *)
  156.  
  157.     function InterpretError (theErr: integer): Str255;
  158.  
  159. implementation
  160.  
  161. (* return the error string that belongs to an error code *)
  162.  
  163.     function InterpretError (theErr: integer): Str255;
  164.         var
  165.             theString: Str255;
  166.             numStr: Str255;
  167.  
  168.     begin
  169.         theString := 'User Error (unknown to the GrafSys)';
  170.         case theErr of
  171.             cNoFFallocated: 
  172.                 theString := 'No FreeForm Matrix allocated';
  173.             cOutOfMem: 
  174.                 theString := 'Memory Manager returned a NIL handle. Out of Memory';
  175.             cBadMethodCall: 
  176.                 theString := 'Method not implemented. You should not call it ';
  177.             cNothingToInherit: 
  178.                 theString := 'There are no FF matrices to inherit. You must allocate at least one before inheriting';
  179.             cTooManyPoints: 
  180.                 theString := 'You exceeded the maximum number of points per object';
  181.             cIllegalPointIndex: 
  182.                 theString := 'The point number you specified does not exist';
  183.             cTooManyLines: 
  184.                 theString := 'You exceeded the maximum number of points per object';
  185.             cIllegalLineIndex: 
  186.                 theString := 'The line number you specified does not exist';
  187.             cCantDeletePoint: 
  188.                 theString := 'The point you want to delete is part of at least one Line. Cannot delete point';
  189.             cNotOwner: 
  190.                 theString := 'The matrix is not owned by the object';
  191.             cBadFF: 
  192.                 theString := 'The matrix you passed is bad (nil?)';
  193.             cBadFFType: 
  194.                 theString := 'The matrix you passed is of a bad type (inherit or passOn)';
  195.             cNo3DWindow: 
  196.                 theString := 'Window you passed is no 3D window';
  197.             cCantCreateOffscreen: 
  198.                 theString := 'Error occured while trying to allocate Off-Screen PixMap. Probably not enough Memory';
  199.             cCantChangeOffscreen: 
  200.                 theString := 'Error occured while trying to resize or recolor Off-Screen PixMap';
  201.             cNoOSAttached: 
  202.                 theString := 'The 3D Window passed has no Off-Screen PixMap attached';
  203.             cCantUseWindowCLUT: 
  204.                 theString := 'Current active window does not use indexed (1-8 bit/pixel) colors';
  205.             cNoActiveOSPixMap: 
  206.                 theString := 'User did not call BeginOSDraw. no active pix map ';
  207.  
  208.             otherwise
  209.                 begin
  210.                     NumToString(theErr, numStr);
  211.                     theString := Concat('ID = ', numStr, ': ??? (InterpretError does not know this one. Fascinating.)');
  212.                 end;
  213.         end; (* case *)
  214.         InterpretError := theString;
  215.     end;
  216.  
  217. {Clone allocates an exact copy of the object }
  218. {this means that the object points to the same FF matrices if an instance of TabstractObject etc}
  219.  
  220.     function TGenericObject.Clone: TGenericObject;
  221.         var
  222.             theHandle: Handle;
  223.     begin
  224.         theHandle := Handle(self);
  225.         ErrorCode := HandToHand(theHandle);
  226.         Clone := TGEnericObject(theHandle);
  227.     end;
  228.  
  229.     procedure TGenericObject.HandleError;
  230.         var
  231.             theString: Str255;
  232.             theItem: integer;
  233.  
  234.     begin
  235.         NumToString(ErrorCode, theString);
  236.         ParamText('I am sorry, GrafSys reports an error:', Concat('Error #', theString, ' = ', InterpretError(ErrorCode)), 'TGenericObject', '');
  237.         theItem := StopAlert(cErrorAlertID, nil);
  238.     end;
  239.  
  240.     procedure TGenericObject.ResetError;
  241.     begin
  242.         ErrorCode := NoErr;
  243.     end;
  244.  
  245.     function TGenericObject.Test (opcode: integer): integer;     (* does anything to check integrity of object         *)
  246.                                                                         (* This incarnation just pops up the Error Dialog    *)
  247.                                                                         (* and returns Error Code. Opcode is ignored         *)
  248.         var
  249.             theString: Str255;
  250.             theItem: integer;
  251.  
  252.     begin
  253.         if errorCode = noErr then
  254.             begin
  255.                 ParamText('GrafSys reports the result of an object-test', 'Test of object succesful.', 'No Error detected', 'TGenericObject.Test');
  256.             end
  257.         else
  258.             begin
  259.                 NumToString(ErrorCode, theString);
  260.                 ParamText('Test of object failed.', Concat('Error #', theString, ' = ', InterpretError(ErrorCode)), 'TGenericObject.Test', '');
  261.             end;
  262.         theItem := NoteAlert(cErrorAlertID, nil);
  263.         Test := ErrorCode;
  264.     end;
  265.  
  266.     procedure TGenericObject.Kill;
  267.     begin
  268.         DisposHandle(Handle(self));
  269.     end;
  270.  
  271.     procedure TGenericObject.Init;
  272.     begin
  273.         ErrorCode := 0;
  274.     end;
  275.  
  276.     procedure TGenericObject.Reset;
  277.     begin
  278.         ErrorCode := 0;
  279.     end;
  280.  
  281.     procedure TMatrixList.Init;
  282.     begin
  283.         M := Identity;
  284.         next := nil;
  285.     end;
  286.  
  287.     procedure TMatrixList.Reset;
  288.     begin
  289.         inherited Reset;
  290.         M := Identity;
  291.     end;
  292.  
  293. {rotate this matrix further }
  294.     procedure TMatrixList.TMRotate (dx, dy, dz: real);    {rotate this matrix further}
  295.         var
  296.             theMatrix: Matrix4;
  297.             change: boolean;
  298.     begin
  299.         theMatrix := Identity;
  300.         if dx <> 0 then
  301.             begin
  302.                 RotX(theMatrix, dx);
  303.                 change := TRUE;
  304.             end;
  305.         if dy <> 0 then
  306.             begin
  307.                 RotY(theMatrix, dy);
  308.                 change := TRUE;
  309.             end;
  310.         if dz <> 0 then
  311.             begin
  312.                 RotZ(theMatrix, dz);
  313.                 change := TRUE;
  314.             end;
  315.         if change then
  316.             begin
  317.                 Self.M := MMult(Self.M, theMatrix); (* postconcatenate operation*)
  318.             end;
  319.     end;
  320.  
  321.     procedure TMatrixList.TMScale (dx, dy, dz: real);        {scale this matrix further }
  322.     begin
  323.         MScale(self.M, dx, dy, dz);
  324.     end;
  325.  
  326.     procedure TMatrixList.TMTranslate (dx, dy, dz: real);    {Translate this matrix further }
  327.     begin
  328.         MTranslate(self.M, dx, dy, dz);
  329.     end;
  330.  
  331.     procedure TMatrixList.TMRotArbAchsis (p, x: Vector4; phi: real); {rotate around achsis defined by p and x}
  332.     begin
  333.         RotArbitraryAchsis(self.M, p, x, phi);
  334.     end;
  335.  
  336.     procedure TMatrixInherit.Init;
  337.         override;
  338.     begin
  339.         inherited Init;
  340.         upLink := nil;
  341.     end;
  342.     procedure TMatrixPass.Init;
  343.         override;
  344.     begin
  345.         inherited Init;
  346.         downLink := nil;
  347.     end;
  348.  
  349.     procedure Tabstract3DObject.Init;
  350.         override;
  351.     begin
  352.         inherited Init;
  353.         if ErrorCode <> noErr then
  354.             Exit(init);
  355.         currentFF := nil;
  356.         FFMatrix := nil; {no FF matrix allocated so far }
  357.         xForm := Identity;
  358.         arbRot := Identity;
  359.         xTrans := 0;
  360.         yTrans := 0;
  361.         zTrans := 0;
  362.         xScale := 1;
  363.         yScale := 1;
  364.         zScale := 1;
  365.         xRot := 0;
  366.         yRot := 0;
  367.         zRot := 0;
  368.         ErrorCode := 0;
  369.         objChanged := FALSE;
  370.         hasChanged := FALSE;
  371.         versionsID := -1; (* minimum eye setting is zero *)
  372.     end;
  373.  
  374. {the clone method will also clone all FFmatrices. If we run into a TMInherit we insert a new passon in father }
  375. {to this clone of son. If we encounter a passon, it is skipped and not cloned                                            }
  376.  
  377.     function Tabstract3DObject.Clone: TGenericObject;                    {must also clone all TMatrix }
  378.         override;                                                                    {ATTN: what about inheritances??}
  379.  
  380.         var
  381.             theClone: Tabstract3DObject;
  382.             walker: TMatrixList; (* with this we walk down the original *)
  383.             CloneWalker: TMatrixList; (* with this we walk down the clone's list *)
  384.             MatrixClone: TMatrixList; (* this is the clone of the matrix *)
  385.             passClone: TMatrixPass; (* this is the clone of father's pass on if we hit a TMatrixInherit *)
  386.  
  387.     begin
  388.         theClone := Tabstract3DObject(inherited Clone);
  389.         walker := self.FFMatrix; (* get the first ffMatrix *)
  390.         CloneWalker := theClone.FFMatrix;
  391.         while walker <> nil do (* clone if not of type TMatrixPass *)
  392.             begin
  393.                 if Member(walker, TMatrixPass) then (* do nothing ! *)
  394.                 else
  395.                     begin
  396.                         MatrixClone := TMatrixList(walker.Clone);
  397.                         MatrixClone.owner := theClone;
  398.                         TMatrixInherit(MatrixClone).MeTheSon := theClone;
  399.                         CloneWalker.next := MatrixClone;
  400.                         if Member(MatrixClone, TMatrixInherit) then (* we must insert a inherit block into fathers FF list *)
  401.                             begin
  402.                                 passClone := TMatrixPass(TMatrixInherit(MatrixClone).upLink.Clone); (* owner is already set correctly *)
  403.                                 passClone.downLink := TMatrixInherit(MatrixClone);
  404.                                 TMatrixInherit(MatrixClone).upLink.next := passClone;     (* insert into fathers list. Don't need to update     *)
  405.                                                                                 (*passClone.next  since it already points to the     *)
  406.                                                                                 (*correct object                                           *)
  407.                                 TMatrixInherit(MatrixClone).upLink := passClone; (* destroy last reference to original *)
  408.                             end;
  409.                         CloneWalker := CloneWalker.next; (* advance clonewalker *)
  410.                         MatrixClone.next := nil; (* failsafe in case a skipped follows last *)
  411.                     end;
  412.                 walker := walker.next; (* advance *)
  413.             end; (* while *)
  414.         Clone := theClone;
  415.     end;
  416.  
  417.     procedure Tabstract3DObject.Reset;
  418.         override;
  419.         var
  420.             walker: TMatrixList;
  421.  
  422.     begin
  423.         inherited Reset;
  424.         xForm := Identity;
  425.         arbRot := Identity;
  426.         xTrans := 0;
  427.         yTrans := 0;
  428.         zTrans := 0;
  429.         xScale := 1;
  430.         yScale := 1;
  431.         zScale := 1;
  432.         xRot := 0;
  433.         yRot := 0;
  434.         zRot := 0;
  435.         ErrorCode := 0;
  436.         objChanged := FALSE;
  437.         hasChanged := TRUE;
  438. (* now reset all FF matrices that are in the chain *)
  439.         walker := FFMatrix;
  440.         while walker <> nil do
  441.             begin
  442.                 walker.Reset;
  443.                 walker := walker.next;
  444.             end;
  445.     end;
  446.  
  447. { xlate object : we only update the _Trans coordinates (objects origin). from this we }
  448. {                       generate the real translation matrix later if we call Transform          }
  449.  
  450.     procedure Tabstract3DObject.Translate (dx, dy, dz: real);
  451.     begin
  452.         xTrans := xTrans + dx;
  453.         yTrans := yTrans + dy;
  454.         zTrans := zTrans + dz;
  455.         objChanged := TRUE;
  456.     end;
  457.  
  458. { xlate object : we only update the _Trans coordinates (objects origin). from this we }
  459. {                       generate the real translation matrix later if we call Transform          }
  460.  
  461.     procedure Tabstract3DObject.SetTranslation (x, y, z: real);
  462.     begin
  463.         xTrans := x;
  464.         yTrans := y;
  465.         zTrans := z;
  466.         objChanged := TRUE;
  467.     end;
  468.  
  469.     procedure Tabstract3DObject.Rotate (dx, dy, dz: real);                  { rotate further (just changes x-,y- and zrot) }
  470.     begin
  471.         xRot := xRot + dx;
  472.         yRot := yRot + dy;
  473.         zRot := zRot + dz;
  474.         objChanged := TRUE;
  475.     end;
  476.  
  477.     procedure Tabstract3DObject.SetRotation (x, y, z: real);              { set rot to x,y and z }
  478.     begin
  479.         xRot := x;
  480.         yRot := y;
  481.         zRot := z;
  482.         objChanged := TRUE;
  483.     end;
  484.  
  485.     procedure Tabstract3DObject.Scale (dx, dy, dz: real);                  {scale factor for x, y and z }
  486.     begin
  487.         xScale := xScale + dx;
  488.         yScale := yScale + dy;
  489.         zScale := zScale + dz;
  490.         objChanged := TRUE;
  491.     end;
  492.  
  493.  
  494.     procedure Tabstract3DObject.SetScale (x, y, z: real);                  {set absolute scale factor }
  495.     begin
  496.         xScale := x;
  497.         yScale := y;
  498.         zScale := z;
  499.         objChanged := TRUE;
  500.     end;
  501.  
  502.     procedure Tabstract3DObject.RotArb (p, x: Vector4; phi: real);
  503.     begin
  504.         RotArbitraryAchsis(arbRot, p, x, phi);
  505.     end;
  506.  
  507.     procedure Tabstract3DObject.ResetArb;
  508.     begin
  509.         arbRot := Identity;
  510.     end;
  511.  
  512. {translate currentFF for dx,dy and dz *)
  513.     procedure Tabstract3DObject.FFTranslate (dx, dy, dz: real);          {xlate current FFMatrix further }
  514.     begin
  515.         if currentFF = nil then
  516.             ErrorCode := cNoFFallocated
  517.         else
  518.             begin
  519.                 MTranslate(currentFF.M, dx, dy, dz);
  520.                 objChanged := TRUE;
  521.             end;
  522.     end;
  523.  
  524.  
  525.     procedure Tabstract3DObject.FFRotate (dx, dy, dz: real);              {rotate current FFMatrix further }
  526.         var
  527.             theMatrix: Matrix4;
  528.             change: Boolean;
  529.  
  530.     begin
  531.         if currentFF = nil then
  532.             ErrorCode := cNoFFallocated
  533.         else
  534.             begin
  535.                 theMatrix := Identity;
  536.                 if dx <> 0 then
  537.                     begin
  538.                         RotX(theMatrix, dx);
  539.                         change := TRUE;
  540.                     end;
  541.                 if dy <> 0 then
  542.                     begin
  543.                         RotY(theMatrix, dy);
  544.                         change := TRUE;
  545.                     end;
  546.                 if dz <> 0 then
  547.                     begin
  548.                         RotZ(theMatrix, dz);
  549.                         change := TRUE;
  550.                     end;
  551.                 if change then
  552.                     begin
  553.                         currentFF.M := MMult(currentFF.M, theMatrix); (* postconcatenate operation*)
  554.                         objChanged := TRUE;
  555.                     end;
  556.             end;
  557.     end;
  558.  
  559.     procedure Tabstract3DObject.FFScale (dx, dy, dz: real);              {scale current FFMatrix further }
  560.  
  561.     begin
  562.         if currentFF = nil then
  563.             ErrorCode := cNoFFallocated
  564.         else
  565.             begin
  566.                 MScale(currentFF.M, dx, dy, dz);
  567.                 objChanged := TRUE;
  568.             end;
  569.     end;
  570.  
  571.     procedure Tabstract3DObject.FFRotArbAchsis (p, x: Vector4; phi: real); {rotate around achsis defined by p and x}
  572.  
  573.     begin
  574.         if currentFF = nil then
  575.             ErrorCode := cNoFFallocated
  576.         else
  577.             begin
  578.                 RotArbitraryAchsis(currentFF.M, p, x, phi);
  579.                 objChanged := TRUE;
  580.             end;
  581.     end;
  582.  
  583.  
  584.     procedure Tabstract3DObject.FFReset;                                {resets *current* FFMatrix to Identity (i.e. not all) }
  585.     begin
  586.         if currentFF = nil then
  587.             ErrorCode := cNoFFallocated
  588.         else
  589.             begin
  590.                 currentFF.M := Identity;
  591.                 objChanged := TRUE;
  592.             end;
  593.     end;
  594.  
  595.     procedure Tabstract3DObject.FFInherit (var FatherList: TMatrixPass);    {concatenate Fathers list to current FF List }
  596.         var
  597.             listTemp: TMatrixInherit;
  598.             walker: TMatrixList;
  599.  
  600.     begin
  601.  
  602.         if FatherList = nil then (* nothing to concat *)
  603.             begin
  604.                 ErrorCode := cBadFF;
  605.                 exit(FFInherit);
  606.             end;
  607.  
  608.         New(ListTemp); (* allocate memory for matrix and link fields *)
  609.         if ListTemp = nil then
  610.             begin
  611.                 ErrorCode := cOutOfMem;
  612.                 Exit(FFInherit);
  613.             end;
  614.  
  615.         listTemp.Init; {init to identity, will be updated when father is Transformed. next is set to nil }
  616.         listTemp.owner := self;
  617.  
  618. (* now look for end to list and append myself to list *)
  619.         walker := self.FFMatrix; (* load first matrix or nil if none allocated *)
  620.         if walker = nil then
  621.             self.FFMatrix := listTemp
  622.         else
  623.             begin
  624.                 while walker.next <> nil do (* look for end of list *)
  625.                     walker := walker.next;
  626.                 walker.next := ListTemp; (* put at end *)
  627.             end;
  628.  
  629. (* now link the pass and inherit matrices *)
  630.         ListTemp.next := nil; (* failsafe, postconcat *)
  631.         ListTemp.upLink := fatherList;
  632.         FatherList.downLink := ListTemp;
  633.         listTemp.meTheSon := self; (* required so father can kill son if he himself receives kill msg *)
  634.         objChanged := TRUE;
  635.     end;
  636.  
  637.  
  638.     function Tabstract3DObject.FFNewPostConcat: TMatrixList;            {allocate new FF matrix and postconcat it, put it into currentFF}
  639.         var
  640.             temp: TMatrixList;
  641.  
  642.     begin
  643.         NEW(currentFF);
  644.         if currentFF = nil then
  645.             begin
  646.                 ErrorCode := cOutOfMem;
  647.                 Exit(FFNewPostConcat);
  648.             eract3DObject.ForeignPoint (p: Vector4): Vector4;
  649.     begin
  650.         ForeignPoint := VMult(p, xForm)
  651.     end;
  652.  
  653.     function Tabstract3DObject.WorldToModel (wc: Vector4): Vector4; {xform world coordinates to model coordinates}
  654.  
  655.         var
  656.             wcOrigin: Vector4;
  657.             Origin: vector4;
  658.  
  659.     begin
  660.         SetVector4(Origin, 0, 0, 0); (* model coordinate origin *)
  661.         wcOrigin := ForeignPoint(Origin); (* get the origin in wc *)
  662.         WorldToModel := VSub(wc, wcOrigin); (* subtract global origin from global point to get local point *)
  663.     end;
  664.  
  665.     procedure Tabstract3DObject.Draw;                                    {not supported at this level }
  666.     begin
  667.         ErrorCode := cBadMethodCall;
  668.     end;
  669.  
  670.     procedure Tabstract3DObject.Kill;                    {deallocate memory for this object. it will call kill for }
  671.         override;                                                {all associated FF matrices. If it passes on, it will deallocate }
  672.                                                             {all sons and their FF matrices as well}
  673.         var
  674.             currentMatrix: TMatrixList;
  675.             nextMatrix: TMatrixList;
  676.             sonsLink: TMatrixInherit;
  677.             son: Tabstract3DObject;
  678.  
  679.     begin
  680.     {begin by deallocating all FFMatrices}
  681.         currentMatrix := FFmatrix;
  682.         while currentMatrix <> nil do
  683.             begin
  684.                 nextMatrix := currentMatrix.next;
  685.                 if Member(currentMatrix, TMatrixPass) then {kill son if alive. this is done in four steps: }
  686.                     begin
  687.                         sonsLink := TMatrixPass(currentMatrix).downLink; (* get to his link-up matrix (Step 1) *)
  688.                         son := sonsLink.meTheSon; (* get himself (Step 2) *)
  689.                         if son <> nil then (* son still alive? *)
  690.                             son.kill; (* tell son to kill himself and all his FF matrices except his link-up field(Step 3) *)
  691.                         sonsLink.kill; (* deallocate mem for sons uplink (Step 4) *)
  692.                         currentMatrix.kill; (* finally, deallocate the downlink too *)
  693.                     end
  694.                 else if Member(currentMatrix, TMatrixInherit) then     {just eliminate the link to this object and             }
  695.                     begin                                                        {do not deallocate. this is done when father dies.    }
  696.                         TMatrixInherit(currentMatrix).meTheSon := nil;     (* just remove reference *)
  697.                     end
  698.                 else {the matrix is normal calculation type. deallocate it }
  699.                     begin
  700.                         currentMatrix.kill;
  701.                     end;
  702.  
  703.                 currentMatrix := nextMatrix;
  704.             end; (* while *)
  705.         inherited kill; (* suicide *)
  706.     end;
  707.  
  708.  
  709. end. {implementation }